﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using DeenGames.Utils;
using Redbrick.Silverlight.Common;
using Redbrick.Silverlight.Serialization;
using System.ComponentModel;

namespace Moria
{
	public interface IOption { }

	public class Option<_type> : IOption
	{

		public Option(string prompt, _type value)
		{
			this.DebugMethodInfo(prompt, value);
			this.Prompt = prompt;
			this.Value = value;
		}

		/// <summary>
		/// was o_prompt
		/// </summary>
		public string Prompt { get; private set; }

		/// <summary>
		/// was o_var
		/// </summary>
		public _type Value { get; set; }

	}

	public class GameOptions : Observable, IEnumerable<IOption>
	{

		#region Consts & Settings

		private const string OptionsFileKey = "moriaOptions";

		#endregion Consts & Settings

		#region Declarations

		static Lazy<GameOptions> instance = new Lazy<GameOptions>(() => new GameOptions());
		public static GameOptions Instance { get { return instance.Value; } }


		private List<IOption> _options = null;

		#endregion Declarations

		#region Constructor

		private GameOptions()
		{
			this.DebugMethodInfo();
			if (!this.Load())
			{
				_options = new List<IOption>()
				{
					new Option<bool>("Running: cut known corners",true),				// find_cut
					new Option<bool>("Running: examine potential corners",true),	// find_examine
					new Option<bool>("Running: print self during run",false),			// find_prself
					new Option<bool>("Running: stop when map sector changes",false),// find_bound
					new Option<bool>("Running: run through open doors",false),		// find_ignore_doors
					new Option<bool>("Prompt to pick up objects",false),				// prompt_carry_flag
					new Option<bool>("Rogue like commands",false),						// rogue_like_commands
					new Option<bool>("Show weights in inventory",false),				// show_weight_flag
					new Option<bool>("Highlight and notice mineral seams",false),	// highlight_seams
					new Option<bool>("Beep for invalid character",true),				// sound_beep_flag
					new Option<bool>("Display rest/repeat counts",true),				// display_counts
				};
			}
		}

		#endregion Constructor

		#region Methods

		protected override bool OnPropertyChanged(PropertyChangedEventArgs args)
		{
			this.Save();	
			return base.OnPropertyChanged(args);
		}

		public bool Save()
		{
			this.DebugMethodInfo();

			try
			{
				PersistentStorage.Store(OptionsFileKey, this._options);
				return true;
			}
			catch (Exception err)
			{
				Debug.WriteLine("Exception while saving options: " + err);
				throw err;
			}
		}
		public bool Load()
		{
			this.DebugMethodInfo();
			this._options = PersistentStorage.Retrieve<List<IOption>>(OptionsFileKey);
			return this._options != null && this._options.Count > 0;
		}
		
		public IEnumerator<IOption> GetEnumerator()
		{
			return this._options.GetEnumerator();
		}
		 IEnumerator IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}

		#endregion Methods

		#region Events


		#endregion Events

		#region Properties

		public IOption this[int ndx]
		{
			get { return this._options[ndx]; }
			set { this._options[ndx] = value; }
		}

		public bool find_cut
		{
			get { return ((Option<bool>)this[0]).Value; }
			set
			{
				((Option<bool>)this[0]).Value = value;
				RaisePropertyChanged(() => this.find_cut);
			}
		}
		public bool find_examine
		{
			get { return ((Option<bool>)this[1]).Value; }
			set
			{
				((Option<bool>)this[1]).Value = value;
				RaisePropertyChanged(() => this.find_examine);
			}
		}
		public bool find_prself
		{
			get { return ((Option<bool>)this[2]).Value; }
			set
			{
				((Option<bool>)this[2]).Value = value;
				RaisePropertyChanged(() => this.find_prself);
			}
		}
		public bool find_bound
		{
			get { return ((Option<bool>)this[3]).Value; }
			set
			{
				((Option<bool>)this[3]).Value = value;
				RaisePropertyChanged(() => this.find_bound);
			}
		}
		public bool find_ignore_doors
		{
			get { return ((Option<bool>)this[4]).Value; }
			set
			{
				((Option<bool>)this[4]).Value = value;
				RaisePropertyChanged(() => this.find_ignore_doors);
			}
		}
		public bool prompt_carry_flag
		{
			get { return ((Option<bool>)this[5]).Value; }
			set
			{
				((Option<bool>)this[5]).Value = value;
				RaisePropertyChanged(() => this.prompt_carry_flag);
			}
		}
		public bool rogue_like_commands
		{
			get { return ((Option<bool>)this[6]).Value; }
			set
			{
				((Option<bool>)this[6]).Value = value;
				RaisePropertyChanged(() => this.rogue_like_commands);
			}
		}
		public bool show_weight_flag
		{
			get { return ((Option<bool>)this[7]).Value; }
			set
			{
				((Option<bool>)this[7]).Value = value;
				RaisePropertyChanged(() => this.show_weight_flag);
			}
		}
		public bool highlight_seams
		{
			get { return ((Option<bool>)this[8]).Value; }
			set
			{
				((Option<bool>)this[8]).Value = value;
				RaisePropertyChanged(() => this.highlight_seams);
			}
		}
		public bool sound_beep_flag
		{
			get { return ((Option<bool>)this[9]).Value; }
			set
			{
				((Option<bool>)this[9]).Value = value;
				RaisePropertyChanged(() => this.sound_beep_flag);
			}
		}
		public bool display_counts
		{
			get { return ((Option<bool>)this[10]).Value; }
			set
			{
				((Option<bool>)this[10]).Value = value;
				RaisePropertyChanged(() => this.display_counts);
			}
		}

		#endregion Properties
	}

	[Serializer(typeof(GameOptions))]
	public class GameOptionsSerializer : ISerializeObject
	{
		public object[] Serialize(object target)
		{
			List<IOption> options = target as List<IOption>;
			if (options != null)
			{
				object[] ot = new object[options.Count];
				options.ForEach((ndx, val) => ot[ndx] = val);
				return ot;
			}
			return null;
		}

		public object Deserialize(object[] data)
		{
			List<IOption> options = new List<IOption>();
			if (options != null)
			{
				data.ForEach((val) => options.Add((IOption)val));
				return options;
			}
			return null;
		}
	}

}
